package com.happywynne.elasticsearchtravel.controller;

import com.alibaba.fastjson.JSON;
import com.happywynne.elasticsearchtravel.consts.TravelConsts;
import com.happywynne.elasticsearchtravel.pojo.TrashBinTravel;
import com.happywynne.elasticsearchtravel.pojo.bo.ProvinceRegionCountingBO;
import com.happywynne.elasticsearchtravel.util.ElasticSearchUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.core.CountResponse;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author Wynne.Lu
 * @date 2021/1/29 下午4:10
 * @desc
 */
@Slf4j
@RestController
@RequestMapping("/trash-bin-travel")
public class TrashBinController {
    /**
     * 该桶的所有运行数据
     *
     * @param binCode 桶代码
     * @return 桶旅程
     */
    @GetMapping("/bin-code/{binCode}")
    public TrashBinTravel queryTravelByBinCode(@PathVariable(name = "binCode") String binCode) throws IOException {
        log.info("调用接口 /bin-code/{}", binCode);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchPhraseQuery("bin.binCode.keyword", binCode));
        SearchResponse response = ElasticSearchUtil.search(TravelConsts.TRAVEL_INDEX_NAME, searchSourceBuilder);

        Optional<SearchHit> hitOptional = ElasticSearchUtil.getOrEmpty(response);

        return hitOptional.map(documentFields ->
                JSON.parseObject(documentFields.getSourceAsString(), TrashBinTravel.class)).orElse(null);
    }

    /**
     * 可以根据省份，市，区查询在指定位置的垃圾桶 ，为了方便 这里显示省级
     *
     * @param provinceCode 省级代码
     * @param regionCode   市级代码
     * @return 桶旅程
     */
    @GetMapping("/province-travel/{provinceCode}/{regionCode}")
    public String queryTravelByProvinceCode(@PathVariable(name = "provinceCode") String provinceCode,
                                            @PathVariable(name = "regionCode") String regionCode) throws IOException {
        log.info("调用接口 /current-province/{}/{}", provinceCode, regionCode);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(
                QueryBuilders.boolQuery()
                        .must(QueryBuilders.matchPhraseQuery("currentAddress.provinceCode.keyword", provinceCode))
                        .must(QueryBuilders.matchPhraseQuery("address.regionCode.keyword", regionCode))
        );
        // prepareSearchScroll
        SearchResponse response = ElasticSearchUtil.search(TravelConsts.TRAVEL_INDEX_NAME, searchSourceBuilder);

        List<String> data = new ArrayList<>();
        for (SearchHit hit : response.getHits().getHits()) {
            data.add(hit.getSourceAsString());
        }
        return JSON.toJSONString(data);
    }

    /**
     * 可以根据省份，市，区查询在指定位置的垃圾桶 ，为了方便 这里显示省级
     *
     * @param provinceCode 省级代码
     * @return 数量
     */
    @GetMapping("/province-travel/count/{provinceCode}/{regionCode}")
    public Long queryCountByProvinceCode(@PathVariable(name = "provinceCode") String provinceCode,
                                         @PathVariable(name = "regionCode") String regionCode) throws IOException {
        log.info("调用接口 /current-province/count/{}/{}", provinceCode, regionCode);

        AbstractQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.matchPhraseQuery("currentAddress.provinceCode.keyword", provinceCode))
                .must(QueryBuilders.matchPhraseQuery("address.regionCode.keyword", regionCode));
        CountResponse response = ElasticSearchUtil.searchCount(TravelConsts.TRAVEL_INDEX_NAME, boolQueryBuilder);


        return response.getCount();
    }

    /**
     * 可以根据省份，市，区查询在指定位置的垃圾桶 ，为了方便 这里显示省级
     *
     * @param provinceCode 省级代码
     * @return 数量
     */
    @GetMapping("/province-travel/count/{provinceCode}")
    public ProvinceRegionCountingBO queryRegionCountByProvinceCode(@PathVariable(name = "provinceCode") String provinceCode) throws IOException {
        log.info("调用接口 /province-travel/count/{}", provinceCode);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchPhraseQuery("currentAddress.provinceCode.keyword", provinceCode));

        TermsAggregationBuilder aggProvinceCount = AggregationBuilders.terms("aggProvinceCount").field("currentAddress.provinceCode.keyword");
        TermsAggregationBuilder aggRegionCount = AggregationBuilders.terms("aggRegionCount").field("currentAddress.regionCode.keyword").size(100);

        searchSourceBuilder.aggregation(aggProvinceCount);
        searchSourceBuilder.aggregation(aggRegionCount);

        SearchResponse response = ElasticSearchUtil.search(TravelConsts.TRAVEL_INDEX_NAME, searchSourceBuilder);
        //FIXME validate null
        ProvinceRegionCountingBO provinceRegionCountingBO = new ProvinceRegionCountingBO();
        Terms provinceTerms = response.getAggregations().get("aggProvinceCount");
        for (Terms.Bucket provinceBucket : provinceTerms.getBuckets()) {
            provinceRegionCountingBO.setProvinceCode(provinceBucket.getKeyAsString());
            provinceRegionCountingBO.setProvinceCount(provinceBucket.getDocCount());
        }
        Terms regionTerms = response.getAggregations().get("aggRegionCount");
        for (Terms.Bucket bucket : regionTerms.getBuckets()) {
            provinceRegionCountingBO.getRegionCountingMap().put(bucket.getKeyAsString(), bucket.getDocCount());
        }

        return provinceRegionCountingBO;
    }

    /**
     * 查询哪天发货的批次，可以更变另外的数据结构，加快查询。
     * 此数据结构勉强支持。
     *
     * @param shippingTime 发货时间
     * @return 桶旅程
     */
    @GetMapping("/shipping-time/{shippingTime}")
    public List<TrashBinTravel> queryTravelByTravelBeginTime(@PathVariable(name = "shippingTime") String shippingTime) {
        log.info("调用接口 /shipping-time/{}", shippingTime);
        return null;
    }

    /**
     * 查询哪天发货的批次，可以更变另外的数据结构，加快查询。
     * 此数据结构勉强支持。
     *
     * @param shippingTime 发货时间
     * @return 数量
     */
    @GetMapping("/shipping-time/count/{shippingTime}")
    public Integer queryCountByTravelBeginTime(@PathVariable(name = "shippingTime") String shippingTime) {
        log.info("调用接口 /shipping-time/{}", shippingTime);
        return null;
    }


}
